#include "lastError.h"

#include "cvtColor.cuh"
#include "../cvtColor.h"

namespace Image2D
{

int rgbToNv12   (const Image2D_Ptr& input, Image2D_Ptr& output)
{
    if((int)(input.type()) != (int)(ImageType::IMAGE_UNSIGNED_CHAR) && (int)(output.type()) != (int)(ImageType::IMAGE_UNSIGNED_CHAR))
    {
        LastError::setLastError("error: Image2D_Ptr type must unsigned char", -1);
        return LastError::getLastErrorCode();
    }

    int numX = 32;
    int numY = 8;

    unsigned int offsetX = static_cast<unsigned int>(input.width());
    unsigned int offsetY = static_cast<unsigned int>(input.height());
    dim3 threadNums(numX, numY, 1);
    dim3 blockNums((offsetX + numX - 1) / numX, (offsetY + numY - 1) / numY, 1);

    __rgbToNv12 << < blockNums, threadNums>> > (
        (const unsigned char*)input.data(0), input.linesize(0),
        (unsigned char*)output.data(0), output.linesize(0),
        (unsigned char*)output.data(1), output.linesize(1),
        output.width(), output.height()
    );

    LastError::setLastError("error: rgbToNv12");
    return LastError::getLastErrorCode();
}

int rgbToYuv420p(const Image2D_Ptr& input, Image2D_Ptr& output)
{
    if((int)(input.type()) != (int)(ImageType::IMAGE_UNSIGNED_CHAR) && (int)(output.type()) != (int)(ImageType::IMAGE_UNSIGNED_CHAR))
    {
        LastError::setLastError("error: Image2D_Ptr type must unsigned char", -1);
        return LastError::getLastErrorCode();
    }

    int numX = 32;
    int numY = 8;

    unsigned int offsetX = static_cast<unsigned int>(input.width());
    unsigned int offsetY = static_cast<unsigned int>(input.height());
    dim3 threadNums(numX, numY, 1);
    dim3 blockNums((offsetX + numX - 1) / numX, (offsetY + numY - 1) / numY, 1);

    __rgbToYuv420p << < blockNums, threadNums>> > (
        (const unsigned char*)input.data(0), input.linesize(0),
        (unsigned char*)output.data(0), output.linesize(0),
        (unsigned char*)output.data(1), output.linesize(1),
        (unsigned char*)output.data(2), output.linesize(2),
        output.width(), output.height()
    );

    LastError::setLastError("error: rgbToYuv420p");
    return LastError::getLastErrorCode();
}

int rgbToBgr    (const Image2D_Ptr& input, Image2D_Ptr& output)
{
    if((int)(input.type()) != (int)(ImageType::IMAGE_UNSIGNED_CHAR) && (int)(output.type()) != (int)(ImageType::IMAGE_UNSIGNED_CHAR))
    {
        LastError::setLastError("error: Image2D_Ptr type must unsigned char", -1);
        return LastError::getLastErrorCode();
    }

    int numX = 32;
    int numY = 8;

    unsigned int offsetX = static_cast<unsigned int>(input.width());
    unsigned int offsetY = static_cast<unsigned int>(input.height());
    dim3 threadNums(numX, numY, 1);
    dim3 blockNums((offsetX + numX - 1) / numX, (offsetY + numY - 1) / numY, 1);

    __rgbToBgr << < blockNums, threadNums>> > (
        (const unsigned char*)input.data(0), input.linesize(0),
        (unsigned char*)output.data(0), output.linesize(0),
        output.width(), output.height()
    );

    LastError::setLastError("error: rgbToBgr");
    return LastError::getLastErrorCode();
}

int nv12ToRgb    (const Image2D_Ptr& input, Image2D_Ptr& output)
{
    if((int)(input.type()) != (int)(ImageType::IMAGE_UNSIGNED_CHAR) && (int)(output.type()) != (int)(ImageType::IMAGE_UNSIGNED_CHAR))
    {
        LastError::setLastError("error: Image2D_Ptr type must unsigned char", -1);
        return LastError::getLastErrorCode();
    }

    int numX = 32;
    int numY = 8;

    unsigned int offsetX = static_cast<unsigned int>(input.width());
    unsigned int offsetY = static_cast<unsigned int>(input.height());
    dim3 threadNums(numX, numY, 1);
    dim3 blockNums((offsetX + numX - 1) / numX, (offsetY + numY - 1) / numY, 1);

    __nv12ToRgb << < blockNums, threadNums>> > (
        (const unsigned char*)input.data(0), input.linesize(0),
        (const unsigned char*)input.data(1), input.linesize(1),
        (unsigned char*)output.data(0), output.linesize(0),
        output.width(), output.height()
    );

    LastError::setLastError("error: nv12ToRgb");
    return LastError::getLastErrorCode();
}

int nv12ToYuv420p(const Image2D_Ptr& input, Image2D_Ptr& output)
{
    if((int)(input.type()) != (int)(ImageType::IMAGE_UNSIGNED_CHAR) && (int)(output.type()) != (int)(ImageType::IMAGE_UNSIGNED_CHAR))
    {
        LastError::setLastError("error: Image2D_Ptr type must unsigned char", -1);
        return LastError::getLastErrorCode();
    }

    int numX = 32;
    int numY = 8;

    unsigned int offsetX = static_cast<unsigned int>(input.width());
    unsigned int offsetY = static_cast<unsigned int>(input.height());
    dim3 threadNums(numX, numY, 1);
    dim3 blockNums((offsetX + numX - 1) / numX, (offsetY + numY - 1) / numY, 1);

    __nv12ToYuv420p << < blockNums, threadNums>> > (
        (const unsigned char*)input.data(0), input.linesize(0),
        (const unsigned char*)input.data(1), input.linesize(1),
        (unsigned char*)output.data(0), output.linesize(0),
        (unsigned char*)output.data(1), output.linesize(1),
        (unsigned char*)output.data(2), output.linesize(2),
        output.width(), output.height()
    );

    LastError::setLastError("error: nv12ToYuv420p");
    return LastError::getLastErrorCode();
}

int nv12ToBgr    (const Image2D_Ptr& input, Image2D_Ptr& output)
{
    if((int)(input.type()) != (int)(ImageType::IMAGE_UNSIGNED_CHAR) && (int)(output.type()) != (int)(ImageType::IMAGE_UNSIGNED_CHAR))
    {
        LastError::setLastError("error: Image2D_Ptr type must unsigned char", -1);
        return LastError::getLastErrorCode();
    }

    int numX = 32;
    int numY = 8;

    unsigned int offsetX = static_cast<unsigned int>(input.width());
    unsigned int offsetY = static_cast<unsigned int>(input.height());
    dim3 threadNums(numX, numY, 1);
    dim3 blockNums((offsetX + numX - 1) / numX, (offsetY + numY - 1) / numY, 1);

    __nv12ToBgr << < blockNums, threadNums>> > (
        (const unsigned char*)input.data(0), input.linesize(0),
        (const unsigned char*)input.data(1), input.linesize(1),
        (unsigned char*)output.data(0), output.linesize(0),
        output.width(), output.height()
    );

    LastError::setLastError("error: nv12ToBgr");
    return LastError::getLastErrorCode();
}

int yuv420pToNv12(const Image2D_Ptr& input, Image2D_Ptr& output)
{
    if((int)(input.type()) != (int)(ImageType::IMAGE_UNSIGNED_CHAR) && (int)(output.type()) != (int)(ImageType::IMAGE_UNSIGNED_CHAR))
    {
        LastError::setLastError("error: Image2D_Ptr type must unsigned char", -1);
        return LastError::getLastErrorCode();
    }

    int numX = 32;
    int numY = 8;

    unsigned int offsetX = static_cast<unsigned int>(input.width());
    unsigned int offsetY = static_cast<unsigned int>(input.height());
    dim3 threadNums(numX, numY, 1);
    dim3 blockNums((offsetX + numX - 1) / numX, (offsetY + numY - 1) / numY, 1);

    __yuv420pToNv12 << < blockNums, threadNums>> > (
        (const unsigned char*)input.data(0), input.linesize(0),
        (const unsigned char*)input.data(1), input.linesize(1),
        (const unsigned char*)input.data(2), input.linesize(2),
        (unsigned char*)output.data(0), output.linesize(0),
        (unsigned char*)output.data(1), output.linesize(1),
        output.width(), output.height()
    );

    LastError::setLastError("error: yuv420pToNv12");
    return LastError::getLastErrorCode();
}

int yuv420pToRgb (const Image2D_Ptr& input, Image2D_Ptr& output)
{
    if((int)(input.type()) != (int)(ImageType::IMAGE_UNSIGNED_CHAR) && (int)(output.type()) != (int)(ImageType::IMAGE_UNSIGNED_CHAR))
    {
        LastError::setLastError("error: Image2D_Ptr type must unsigned char", -1);
        return LastError::getLastErrorCode();
    }

    int numX = 32;
    int numY = 8;

    unsigned int offsetX = static_cast<unsigned int>(input.width());
    unsigned int offsetY = static_cast<unsigned int>(input.height());
    dim3 threadNums(numX, numY, 1);
    dim3 blockNums((offsetX + numX - 1) / numX, (offsetY + numY - 1) / numY, 1);

    __yuv420pToRgb << < blockNums, threadNums>> > (
        (const unsigned char*)input.data(0), input.linesize(0),
        (const unsigned char*)input.data(1), input.linesize(1),
        (const unsigned char*)input.data(2), input.linesize(2),
        (unsigned char*)output.data(0), output.linesize(0),
        output.width(), output.height()
    );

    LastError::setLastError("error: yuv420pToRgb");
    return LastError::getLastErrorCode();
}

int yuv420pToBgr (const Image2D_Ptr& input, Image2D_Ptr& output)
{
    if((int)(input.type()) != (int)(ImageType::IMAGE_UNSIGNED_CHAR) && (int)(output.type()) != (int)(ImageType::IMAGE_UNSIGNED_CHAR))
    {
        LastError::setLastError("error: Image2D_Ptr type must unsigned char", -1);
        return LastError::getLastErrorCode();
    }

    int numX = 32;
    int numY = 8;

    unsigned int offsetX = static_cast<unsigned int>(input.width());
    unsigned int offsetY = static_cast<unsigned int>(input.height());
    dim3 threadNums(numX, numY, 1);
    dim3 blockNums((offsetX + numX - 1) / numX, (offsetY + numY - 1) / numY, 1);

    __yuv420pToBgr << < blockNums, threadNums>> > (
        (const unsigned char*)input.data(0), input.linesize(0),
        (const unsigned char*)input.data(1), input.linesize(1),
        (const unsigned char*)input.data(2), input.linesize(2),
        (unsigned char*)output.data(0), output.linesize(0),
        output.width(), output.height()
    );

    LastError::setLastError("error: yuv420pToBgr");
    return LastError::getLastErrorCode();
}


int bgrToNv12   (const Image2D_Ptr& input, Image2D_Ptr& output)
{
    if((int)(input.type()) != (int)(ImageType::IMAGE_UNSIGNED_CHAR) && (int)(output.type()) != (int)(ImageType::IMAGE_UNSIGNED_CHAR))
    {
        LastError::setLastError("error: Image2D_Ptr type must unsigned char", -1);
        return LastError::getLastErrorCode();
    }

    int numX = 32;
    int numY = 8;

    unsigned int offsetX = static_cast<unsigned int>(input.width());
    unsigned int offsetY = static_cast<unsigned int>(input.height());
    dim3 threadNums(numX, numY, 1);
    dim3 blockNums((offsetX + numX - 1) / numX, (offsetY + numY - 1) / numY, 1);

    __bgrToNv12 << < blockNums, threadNums>> > (
        (const unsigned char*)input.data(0), input.linesize(0),
        (unsigned char*)output.data(0), output.linesize(0),
        (unsigned char*)output.data(1), output.linesize(1),
        output.width(), output.height()
    );

    LastError::setLastError("error: bgrToNv12");
    return LastError::getLastErrorCode();
}

int bgrToYuv420p(const Image2D_Ptr& input, Image2D_Ptr& output)
{
    if((int)(input.type()) != (int)(ImageType::IMAGE_UNSIGNED_CHAR) && (int)(output.type()) != (int)(ImageType::IMAGE_UNSIGNED_CHAR))
    {
        LastError::setLastError("error: Image2D_Ptr type must unsigned char", -1);
        return LastError::getLastErrorCode();
    }

    int numX = 32;
    int numY = 8;

    unsigned int offsetX = static_cast<unsigned int>(input.width());
    unsigned int offsetY = static_cast<unsigned int>(input.height());
    dim3 threadNums(numX, numY, 1);
    dim3 blockNums((offsetX + numX - 1) / numX, (offsetY + numY - 1) / numY, 1);

    __bgrToYuv420p << < blockNums, threadNums>> > (
        (const unsigned char*)input.data(0), input.linesize(0),
        (unsigned char*)output.data(0), output.linesize(0),
        (unsigned char*)output.data(1), output.linesize(1),
        (unsigned char*)output.data(2), output.linesize(2),
        output.width(), output.height()
    );

    LastError::setLastError("error: bgrToYuv420p");
    return LastError::getLastErrorCode();
}

int bgrToRgb    (const Image2D_Ptr& input, Image2D_Ptr& output)
{
    if((int)(input.type()) != (int)(ImageType::IMAGE_UNSIGNED_CHAR) && (int)(output.type()) != (int)(ImageType::IMAGE_UNSIGNED_CHAR))
    {
        LastError::setLastError("error: Image2D_Ptr type must unsigned char", -1);
        return LastError::getLastErrorCode();
    }

    int numX = 32;
    int numY = 8;

    unsigned int offsetX = static_cast<unsigned int>(input.width());
    unsigned int offsetY = static_cast<unsigned int>(input.height());
    dim3 threadNums(numX, numY, 1);
    dim3 blockNums((offsetX + numX - 1) / numX, (offsetY + numY - 1) / numY, 1);

    __bgrToRgb << < blockNums, threadNums>> > (
        (const unsigned char*)input.data(0), input.linesize(0),
        (unsigned char*)output.data(0), output.linesize(0),
        output.width(), output.height()
    );

    LastError::setLastError("error: bgrToRgb");
    return LastError::getLastErrorCode();
}


int rgbaToBgra(const Image2D_Ptr& input, Image2D_Ptr& output)
{
    if((int)(input.type()) != (int)(ImageType::IMAGE_UNSIGNED_CHAR) && (int)(output.type()) != (int)(ImageType::IMAGE_UNSIGNED_CHAR))
    {
        LastError::setLastError("error: Image2D_Ptr type must unsigned char", -1);
        return LastError::getLastErrorCode();
    }

    int numX = 32;
    int numY = 8;

    unsigned int offsetX = static_cast<unsigned int>(input.width());
    unsigned int offsetY = static_cast<unsigned int>(input.height());
    dim3 threadNums(numX, numY, 1);
    dim3 blockNums((offsetX + numX - 1) / numX, (offsetY + numY - 1) / numY, 1);

    __rgbaToBgra << < blockNums, threadNums>> > (
        (const unsigned char*)input.data(0), input.linesize(0),
        (unsigned char*)output.data(0), output.linesize(0),
        output.width(), output.height()
    );

    LastError::setLastError("error: rgbaToBgra");
    return LastError::getLastErrorCode();
}

int bgraToRgba(const Image2D_Ptr& input, Image2D_Ptr& output)
{
    if((int)(input.type()) != (int)(ImageType::IMAGE_UNSIGNED_CHAR) && (int)(output.type()) != (int)(ImageType::IMAGE_UNSIGNED_CHAR))
    {
        LastError::setLastError("error: Image2D_Ptr type must unsigned char", -1);
        return LastError::getLastErrorCode();
    }

    int numX = 32;
    int numY = 8;

    unsigned int offsetX = static_cast<unsigned int>(input.width());
    unsigned int offsetY = static_cast<unsigned int>(input.height());
    dim3 threadNums(numX, numY, 1);
    dim3 blockNums((offsetX + numX - 1) / numX, (offsetY + numY - 1) / numY, 1);

    __bgraToRgba << < blockNums, threadNums>> > (
        (const unsigned char*)input.data(0), input.linesize(0),
        (unsigned char*)output.data(0), output.linesize(0),
        output.width(), output.height()
    );

    LastError::setLastError("error: bgraToRgba");
    return LastError::getLastErrorCode();;
}

/****************************************************************************************************************************/
int rgbToNv12   (const Image2D_Ptr& input, Image2D_Ptr& output, void* stream)
{
    if((int)(input.type()) != (int)(ImageType::IMAGE_UNSIGNED_CHAR) && (int)(output.type()) != (int)(ImageType::IMAGE_UNSIGNED_CHAR))
    {
        LastError::setLastError("error: Image2D_Ptr type must unsigned char", -1);
        return LastError::getLastErrorCode();
    }

    int numX = 32;
    int numY = 8;

    unsigned int offsetX = static_cast<unsigned int>(input.width());
    unsigned int offsetY = static_cast<unsigned int>(input.height());
    dim3 threadNums(numX, numY, 1);
    dim3 blockNums((offsetX + numX - 1) / numX, (offsetY + numY - 1) / numY, 1);

    __rgbToNv12 << < blockNums, threadNums, 0, (cudaStream_t)stream>> > (
        (const unsigned char*)input.data(0), input.linesize(0),
        (unsigned char*)output.data(0), output.linesize(0),
        (unsigned char*)output.data(1), output.linesize(1),
        output.width(), output.height()
    );

    LastError::setLastError("error: rgbToNv12");
    return LastError::getLastErrorCode();
}

int rgbToYuv420p(const Image2D_Ptr& input, Image2D_Ptr& output, void* stream)
{
    if((int)(input.type()) != (int)(ImageType::IMAGE_UNSIGNED_CHAR) && (int)(output.type()) != (int)(ImageType::IMAGE_UNSIGNED_CHAR))
    {
        LastError::setLastError("error: Image2D_Ptr type must unsigned char", -1);
        return LastError::getLastErrorCode();
    }

    int numX = 32;
    int numY = 8;

    unsigned int offsetX = static_cast<unsigned int>(input.width());
    unsigned int offsetY = static_cast<unsigned int>(input.height());
    dim3 threadNums(numX, numY, 1);
    dim3 blockNums((offsetX + numX - 1) / numX, (offsetY + numY - 1) / numY, 1);

    __rgbToYuv420p << < blockNums, threadNums, 0, (cudaStream_t)stream>> > (
        (const unsigned char*)input.data(0), input.linesize(0),
        (unsigned char*)output.data(0), output.linesize(0),
        (unsigned char*)output.data(1), output.linesize(1),
        (unsigned char*)output.data(2), output.linesize(2),
        output.width(), output.height()
    );

    LastError::setLastError("error: rgbToYuv420p");
    return LastError::getLastErrorCode();
}

int rgbToBgr    (const Image2D_Ptr& input, Image2D_Ptr& output, void* stream)
{
    if((int)(input.type()) != (int)(ImageType::IMAGE_UNSIGNED_CHAR) && (int)(output.type()) != (int)(ImageType::IMAGE_UNSIGNED_CHAR))
    {
        LastError::setLastError("error: Image2D_Ptr type must unsigned char", -1);
        return LastError::getLastErrorCode();
    }

    int numX = 32;
    int numY = 8;

    unsigned int offsetX = static_cast<unsigned int>(input.width());
    unsigned int offsetY = static_cast<unsigned int>(input.height());
    dim3 threadNums(numX, numY, 1);
    dim3 blockNums((offsetX + numX - 1) / numX, (offsetY + numY - 1) / numY, 1);

    __rgbToBgr << < blockNums, threadNums, 0, (cudaStream_t)stream>> > (
        (const unsigned char*)input.data(0), input.linesize(0),
        (unsigned char*)output.data(0), output.linesize(0),
        output.width(), output.height()
    );

    LastError::setLastError("error: rgbToBgr");
    return LastError::getLastErrorCode();
}

int nv12ToRgb    (const Image2D_Ptr& input, Image2D_Ptr& output, void* stream)
{
    if((int)(input.type()) != (int)(ImageType::IMAGE_UNSIGNED_CHAR) && (int)(output.type()) != (int)(ImageType::IMAGE_UNSIGNED_CHAR))
    {
        LastError::setLastError("error: Image2D_Ptr type must unsigned char", -1);
        return LastError::getLastErrorCode();
    }

    int numX = 32;
    int numY = 8;

    unsigned int offsetX = static_cast<unsigned int>(input.width());
    unsigned int offsetY = static_cast<unsigned int>(input.height());
    dim3 threadNums(numX, numY, 1);
    dim3 blockNums((offsetX + numX - 1) / numX, (offsetY + numY - 1) / numY, 1);

    __nv12ToRgb << < blockNums, threadNums, 0, (cudaStream_t)stream>> > (
        (const unsigned char*)input.data(0), input.linesize(0),
        (const unsigned char*)input.data(1), input.linesize(1),
        (unsigned char*)output.data(0), output.linesize(0),
        output.width(), output.height()
    );

    LastError::setLastError("error: nv12ToRgb");
    return LastError::getLastErrorCode();
}

int nv12ToYuv420p(const Image2D_Ptr& input, Image2D_Ptr& output, void* stream)
{
    if((int)(input.type()) != (int)(ImageType::IMAGE_UNSIGNED_CHAR) && (int)(output.type()) != (int)(ImageType::IMAGE_UNSIGNED_CHAR))
    {
        LastError::setLastError("error: Image2D_Ptr type must unsigned char", -1);
        return LastError::getLastErrorCode();
    }

    int numX = 32;
    int numY = 8;

    unsigned int offsetX = static_cast<unsigned int>(input.width());
    unsigned int offsetY = static_cast<unsigned int>(input.height());
    dim3 threadNums(numX, numY, 1);
    dim3 blockNums((offsetX + numX - 1) / numX, (offsetY + numY - 1) / numY, 1);

    __nv12ToYuv420p << < blockNums, threadNums, 0, (cudaStream_t)stream>> > (
        (const unsigned char*)input.data(0), input.linesize(0),
        (const unsigned char*)input.data(1), input.linesize(1),
        (unsigned char*)output.data(0), output.linesize(0),
        (unsigned char*)output.data(1), output.linesize(1),
        (unsigned char*)output.data(2), output.linesize(2),
        output.width(), output.height()
    );

    LastError::setLastError("error: nv12ToYuv420p");
    return LastError::getLastErrorCode();
}

int nv12ToBgr    (const Image2D_Ptr& input, Image2D_Ptr& output, void* stream)
{
    if((int)(input.type()) != (int)(ImageType::IMAGE_UNSIGNED_CHAR) && (int)(output.type()) != (int)(ImageType::IMAGE_UNSIGNED_CHAR))
    {
        LastError::setLastError("error: Image2D_Ptr type must unsigned char", -1);
        return LastError::getLastErrorCode();
    }

    int numX = 32;
    int numY = 8;

    unsigned int offsetX = static_cast<unsigned int>(input.width());
    unsigned int offsetY = static_cast<unsigned int>(input.height());
    dim3 threadNums(numX, numY, 1);
    dim3 blockNums((offsetX + numX - 1) / numX, (offsetY + numY - 1) / numY, 1);

    __nv12ToBgr << < blockNums, threadNums, 0, (cudaStream_t)stream>> > (
        (const unsigned char*)input.data(0), input.linesize(0),
        (const unsigned char*)input.data(1), input.linesize(1),
        (unsigned char*)output.data(0), output.linesize(0),
        output.width(), output.height()
    );

    LastError::setLastError("error: nv12ToBgr");
    return LastError::getLastErrorCode();
}

int yuv420pToNv12(const Image2D_Ptr& input, Image2D_Ptr& output, void* stream)
{
    if((int)(input.type()) != (int)(ImageType::IMAGE_UNSIGNED_CHAR) && (int)(output.type()) != (int)(ImageType::IMAGE_UNSIGNED_CHAR))
    {
        LastError::setLastError("error: Image2D_Ptr type must unsigned char", -1);
        return LastError::getLastErrorCode();
    }

    int numX = 32;
    int numY = 8;

    unsigned int offsetX = static_cast<unsigned int>(input.width());
    unsigned int offsetY = static_cast<unsigned int>(input.height());
    dim3 threadNums(numX, numY, 1);
    dim3 blockNums((offsetX + numX - 1) / numX, (offsetY + numY - 1) / numY, 1);

    __yuv420pToNv12 << < blockNums, threadNums, 0, (cudaStream_t)stream>> > (
        (const unsigned char*)input.data(0), input.linesize(0),
        (const unsigned char*)input.data(1), input.linesize(1),
        (const unsigned char*)input.data(2), input.linesize(2),
        (unsigned char*)output.data(0), output.linesize(0),
        (unsigned char*)output.data(1), output.linesize(1),
        output.width(), output.height()
    );

    LastError::setLastError("error: yuv420pToNv12");
    return LastError::getLastErrorCode();
}

int yuv420pToRgb (const Image2D_Ptr& input, Image2D_Ptr& output, void* stream)
{
    if((int)(input.type()) != (int)(ImageType::IMAGE_UNSIGNED_CHAR) && (int)(output.type()) != (int)(ImageType::IMAGE_UNSIGNED_CHAR))
    {
        LastError::setLastError("error: Image2D_Ptr type must unsigned char", -1);
        return LastError::getLastErrorCode();
    }

    int numX = 32;
    int numY = 8;

    unsigned int offsetX = static_cast<unsigned int>(input.width());
    unsigned int offsetY = static_cast<unsigned int>(input.height());
    dim3 threadNums(numX, numY, 1);
    dim3 blockNums((offsetX + numX - 1) / numX, (offsetY + numY - 1) / numY, 1);

    __yuv420pToRgb << < blockNums, threadNums, 0, (cudaStream_t)stream>> > (
        (const unsigned char*)input.data(0), input.linesize(0),
        (const unsigned char*)input.data(1), input.linesize(1),
        (const unsigned char*)input.data(2), input.linesize(2),
        (unsigned char*)output.data(0), output.linesize(0),
        output.width(), output.height()
    );

    LastError::setLastError("error: yuv420pToRgb");
    return LastError::getLastErrorCode();
}

int yuv420pToBgr (const Image2D_Ptr& input, Image2D_Ptr& output, void* stream)
{
    if((int)(input.type()) != (int)(ImageType::IMAGE_UNSIGNED_CHAR) && (int)(output.type()) != (int)(ImageType::IMAGE_UNSIGNED_CHAR))
    {
        LastError::setLastError("error: Image2D_Ptr type must unsigned char", -1);
        return LastError::getLastErrorCode();
    }

    int numX = 32;
    int numY = 8;

    unsigned int offsetX = static_cast<unsigned int>(input.width());
    unsigned int offsetY = static_cast<unsigned int>(input.height());
    dim3 threadNums(numX, numY, 1);
    dim3 blockNums((offsetX + numX - 1) / numX, (offsetY + numY - 1) / numY, 1);

    __yuv420pToBgr << < blockNums, threadNums, 0, (cudaStream_t)stream>> > (
        (const unsigned char*)input.data(0), input.linesize(0),
        (const unsigned char*)input.data(1), input.linesize(1),
        (const unsigned char*)input.data(2), input.linesize(2),
        (unsigned char*)output.data(0), output.linesize(0),
        output.width(), output.height()
    );

    LastError::setLastError("error: yuv420pToBgr");
    return LastError::getLastErrorCode();
}


int bgrToNv12   (const Image2D_Ptr& input, Image2D_Ptr& output, void* stream)
{
    if((int)(input.type()) != (int)(ImageType::IMAGE_UNSIGNED_CHAR) && (int)(output.type()) != (int)(ImageType::IMAGE_UNSIGNED_CHAR))
    {
        LastError::setLastError("error: Image2D_Ptr type must unsigned char", -1);
        return LastError::getLastErrorCode();
    }

    int numX = 32;
    int numY = 8;

    unsigned int offsetX = static_cast<unsigned int>(input.width());
    unsigned int offsetY = static_cast<unsigned int>(input.height());
    dim3 threadNums(numX, numY, 1);
    dim3 blockNums((offsetX + numX - 1) / numX, (offsetY + numY - 1) / numY, 1);

    __bgrToNv12 << < blockNums, threadNums, 0, (cudaStream_t)stream>> > (
        (const unsigned char*)input.data(0), input.linesize(0),
        (unsigned char*)output.data(0), output.linesize(0),
        (unsigned char*)output.data(1), output.linesize(1),
        output.width(), output.height()
    );

    LastError::setLastError("error: bgrToNv12");
    return LastError::getLastErrorCode();
}

int bgrToYuv420p(const Image2D_Ptr& input, Image2D_Ptr& output, void* stream)
{
    if((int)(input.type()) != (int)(ImageType::IMAGE_UNSIGNED_CHAR) && (int)(output.type()) != (int)(ImageType::IMAGE_UNSIGNED_CHAR))
    {
        LastError::setLastError("error: Image2D_Ptr type must unsigned char", -1);
        return LastError::getLastErrorCode();
    }

    int numX = 32;
    int numY = 8;

    unsigned int offsetX = static_cast<unsigned int>(input.width());
    unsigned int offsetY = static_cast<unsigned int>(input.height());
    dim3 threadNums(numX, numY, 1);
    dim3 blockNums((offsetX + numX - 1) / numX, (offsetY + numY - 1) / numY, 1);

    __bgrToYuv420p << < blockNums, threadNums, 0, (cudaStream_t)stream>> > (
        (const unsigned char*)input.data(0), input.linesize(0),
        (unsigned char*)output.data(0), output.linesize(0),
        (unsigned char*)output.data(1), output.linesize(1),
        (unsigned char*)output.data(2), output.linesize(2),
        output.width(), output.height()
    );

    LastError::setLastError("error: bgrToYuv420p");
    return LastError::getLastErrorCode();
}

int bgrToRgb    (const Image2D_Ptr& input, Image2D_Ptr& output, void* stream)
{
    if((int)(input.type()) != (int)(ImageType::IMAGE_UNSIGNED_CHAR) && (int)(output.type()) != (int)(ImageType::IMAGE_UNSIGNED_CHAR))
    {
        LastError::setLastError("error: Image2D_Ptr type must unsigned char", -1);
        return LastError::getLastErrorCode();
    }

    int numX = 32;
    int numY = 8;

    unsigned int offsetX = static_cast<unsigned int>(input.width());
    unsigned int offsetY = static_cast<unsigned int>(input.height());
    dim3 threadNums(numX, numY, 1);
    dim3 blockNums((offsetX + numX - 1) / numX, (offsetY + numY - 1) / numY, 1);

    __bgrToRgb << < blockNums, threadNums, 0, (cudaStream_t)stream>> > (
        (const unsigned char*)input.data(0), input.linesize(0),
        (unsigned char*)output.data(0), input.linesize(0),
        output.width(), output.height()
    );

    LastError::setLastError("error: bgrToRgb");
    return LastError::getLastErrorCode();
}


int rgbaToBgra(const Image2D_Ptr& input, Image2D_Ptr& output, void* stream)
{
    if((int)(input.type()) != (int)(ImageType::IMAGE_UNSIGNED_CHAR) && (int)(output.type()) != (int)(ImageType::IMAGE_UNSIGNED_CHAR))
    {
        LastError::setLastError("error: Image2D_Ptr type must unsigned char", -1);
        return LastError::getLastErrorCode();
    }

    int numX = 32;
    int numY = 8;

    unsigned int offsetX = static_cast<unsigned int>(input.width());
    unsigned int offsetY = static_cast<unsigned int>(input.height());
    dim3 threadNums(numX, numY, 1);
    dim3 blockNums((offsetX + numX - 1) / numX, (offsetY + numY - 1) / numY, 1);

    __rgbaToBgra << < blockNums, threadNums, 0, (cudaStream_t)stream>> > (
        (const unsigned char*)input.data(0), input.linesize(0),
        (unsigned char*)output.data(0), output.linesize(0),
        output.width(), output.height()
    );

    LastError::setLastError("error: rgbaToBgra");
    return LastError::getLastErrorCode();
}

int bgraToRgba(const Image2D_Ptr& input, Image2D_Ptr& output, void* stream)
{
    if((int)(input.type()) != (int)(ImageType::IMAGE_UNSIGNED_CHAR) && (int)(output.type()) != (int)(ImageType::IMAGE_UNSIGNED_CHAR))
    {
        LastError::setLastError("error: Image2D_Ptr type must unsigned char", -1);
        return LastError::getLastErrorCode();
    }

    int numX = 32;
    int numY = 8;

    unsigned int offsetX = static_cast<unsigned int>(input.width());
    unsigned int offsetY = static_cast<unsigned int>(input.height());
    dim3 threadNums(numX, numY, 1);
    dim3 blockNums((offsetX + numX - 1) / numX, (offsetY + numY - 1) / numY, 1);

    __bgraToRgba << < blockNums, threadNums, 0, (cudaStream_t)stream>> > (
        (const unsigned char*)input.data(0), input.linesize(0),
        (unsigned char*)output.data(0), output.linesize(0),
        output.width(), output.height()
    );

    LastError::setLastError("error: bgraToRgba");
    return LastError::getLastErrorCode();;
}

}